var pixelSize = 2;
var blockSize = (3*pixelSize);
var image;
var has_image = false;

function halftoneQR(QRBytes, controlBytes, image) {

    var canvas = $('#canvas-output').get(0);
    canvas.width = canvas.height = QRBytes.length * (3*pixelSize);
    var ctx = canvas.getContext('2d');
    var background = $('#select-background').val();

    $('#canvas-image, #canvas-threshold, #canvas-pixel').attr({
        width: canvas.width,
        height: canvas.height
    });
    if (has_image) {
        // Re-draw image (incase size changed)
        drawImage();
    }

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    var canvasThreshold = $('#canvas-threshold').get(0);
    var ctxThreshold = canvasThreshold.getContext('2d');

    if (has_image && background === 'image') {
        ctx.drawImage(canvasThreshold, 0, 0, canvas.width, canvas.height);
    }

    for (var byteRow = 0; byteRow < QRBytes.length; byteRow++) {
        for (var byteCell = 0; byteCell < QRBytes[byteRow].length; byteCell++) {

            if ((background === 'image' && !has_image) || background === 'noise') {
                // Draw random bytes
                ctx.fillStyle = 'black';
                for (var subRow = 0; subRow < 3; subRow++) {
                    for (var subCell = 0; subCell < 3; subCell++) {
                        ctx.fillStyle = 'black';
                        if (Math.random() < 0.5) {
                            ctx.fillStyle = 'white';
                        }
                        ctx.fillRect(byteRow * blockSize + (subRow * pixelSize), byteCell * blockSize + (subCell * pixelSize), pixelSize, pixelSize);
                    }
                }
            }

            // Middle Cell
            ctx.fillStyle = QRBytes[byteRow][byteCell] ? 'black' : 'white';
            ctx.fillRect(byteRow * blockSize + pixelSize, byteCell * blockSize + pixelSize, pixelSize, pixelSize);
        }
    }

    // Re-draw control bytes
    for (var byteRow = 0; byteRow < controlBytes.length; byteRow++) {
        for (var byteCell = 0; byteCell < controlBytes[byteRow].length; byteCell++) {
            if (controlBytes[byteRow][byteCell] !== null) {
                if (controlBytes[byteRow][byteCell] === true) {
                    ctx.fillStyle = 'black';
                } else {
                    ctx.fillStyle = 'white';
                }
                ctx.fillRect(byteRow * blockSize, byteCell * blockSize, blockSize, blockSize);
            }
        };
    };

    $('#button-download').attr('href', $('#canvas-output').get(0).toDataURL());

}

function drawImage() {
    var canvasColour = $('#canvas-image').get(0);
    var ctxColour = canvasColour.getContext('2d');

    ctxColour.clearRect(0,0,canvasColour.width, canvasColour.height);
    ctxColour.drawImage(image, 0, 0, canvasColour.width, canvasColour.height);

    drawPixel();
}

function drawPixel() {
    var canvasColour = $('#canvas-image').get(0);
    var canvasPixel = $('#canvas-pixel').get(0);
    var ctxPixel = canvasPixel.getContext('2d');
    var canvasTemp = document.createElement('canvas');
    canvasTemp.width = canvasTemp.height = (canvasPixel.width / pixelSize);
    var ctxTemp = canvasTemp.getContext('2d');

    ctxPixel.imageSmoothingEnabled =
        ctxPixel.mozImageSmoothingEnabled =
        ctxPixel.msImageSmoothingEnabled =
        ctxPixel.webkitImageSmoothingEnabled =
        ctxTemp.imageSmoothingEnabled =
        ctxTemp.mozImageSmoothingEnabled =
        ctxTemp.msImageSmoothingEnabled =
        ctxTemp.webkitImageSmoothingEnabled = false;

    ctxTemp.drawImage(canvasColour, 0, 0, canvasTemp.width, canvasTemp.height);
    ctxPixel.drawImage(canvasTemp, 0, 0, canvasPixel.width, canvasPixel.height);

    drawThreshold();
}

function drawThreshold() {
    var canvasPixel = $('#canvas-pixel').get(0);
    var ctxPixel = canvasPixel.getContext('2d');
    var canvasThreshold = $('#canvas-threshold').get(0);
    var ctxThreshold = canvasThreshold.getContext('2d');

    var pixels = ctxPixel.getImageData(0,0,canvasPixel.width,canvasPixel.height);
    var d = pixels.data;
    var width = Math.sqrt(d.length / 4) / pixelSize;
    for (var i=0; i<d.length; i+=4) {
        var r = d[i];
        var g = d[i+1];
        var b = d[i+2];
        var grey = (r * 0.2126 + g * 0.7152 + b * 0.0722);
        //var v = (grey >= 127) ? 255 : 0;
        //d[i] = d[i+1] = d[i+2] = v;
        d[i] = d[i+1] = d[i+2] = grey;
    }

    for (var i=0; i<d.length; i+=4) {
        var grey = d[i];
        var v = (grey >= 127) ? 255 : 0;

        // Dithering
        var error = (grey - v) / 8;
        var i2 = i / 4;
        var row = Math.floor(i2 / width);
        var cell = i2 % width;

        d[i] = d[i+1] = d[i+2] = v;

        d[(((row + 0) * width) + (cell + 1)) * 4] = d[(((row + 0) * width) + (cell + 1)) * 4 + 1] = d[(((row + 0) * width) + (cell + 1)) * 4 + 2] = d[(((row + 0) * width) + (cell + 1)) * 4] + error;
        d[(((row + 0) * width) + (cell + 2)) * 4] = d[(((row + 0) * width) + (cell + 2)) * 4 + 1] = d[(((row + 0) * width) + (cell + 2)) * 4 + 2] = d[(((row + 0) * width) + (cell + 2)) * 4] + error;
        d[(((row + 1) * width) + (cell - 1)) * 4] = d[(((row + 1) * width) + (cell - 1)) * 4 + 1] = d[(((row + 1) * width) + (cell - 1)) * 4 + 2] = d[(((row + 1) * width) + (cell - 1)) * 4] + error;
        d[(((row + 1) * width) + (cell + 0)) * 4] = d[(((row + 1) * width) + (cell + 0)) * 4 + 1] = d[(((row + 1) * width) + (cell + 0)) * 4 + 2] = d[(((row + 1) * width) + (cell + 0)) * 4] + error;
        d[(((row + 1) * width) + (cell + 1)) * 4] = d[(((row + 1) * width) + (cell + 1)) * 4 + 1] = d[(((row + 1) * width) + (cell + 1)) * 4 + 2] = d[(((row + 1) * width) + (cell + 1)) * 4] + error;
        d[(((row + 2) * width) + (cell + 0)) * 4] = d[(((row + 2) * width) + (cell + 0)) * 4 + 1] = d[(((row + 2) * width) + (cell + 0)) * 4 + 2] = d[(((row + 2) * width) + (cell + 0)) * 4] + error;
    }
    ctxThreshold.putImageData(pixels, 0, 0);
}

$('body').on('dragover', function(e) {
    e.preventDefault();
    $('body').addClass('hover');
});
$('#drop-overlay').on('dragend dragleave', function(e) {
    e.preventDefault();
    $('body').removeClass('hover');
});
$('#drop-overlay').on('drop', function(e) {
    e.preventDefault();
    $('body').removeClass('hover');

    var file = e.originalEvent.dataTransfer.files[0],
        reader = new FileReader();
    reader.onload = function(event) {
        //event.target.result;
        var imageColour = new Image();
        imageColour.onload = function() {
            has_image = true;
            image = this;
            drawImage();
        }
        imageColour.src = event.target.result;
    };
    reader.readAsDataURL(file);

    return false;
});

$(function() {

    $('#button-generate').on('click', function() {
        var text = $('#input-content').val();

        var errorLevel = $('#select-redundancy').val();

        var sizes = {
            L: [152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 1240],
            M: [128, 224, 352, 512, 688, 864,  992,  700,  700,  524],
            Q: [104, 176, 272, 384, 286, 608,  508,  376,  608,  434],
            H: [72,  128, 208, 288, 214, 480,  164,  296,  464,  346]
        };

        var userSize = parseInt($('#select-size').val());
        var QRsize = -1;
        if (userSize === 0) {
            for (var i = 0; i < sizes[errorLevel].length; i++) {
                if (text.length < sizes[errorLevel][i]) {
                    QRsize = i + 1;
                    break;
                }
            };
        } else {
            if (text.length < sizes[errorLevel][userSize - 1]) {
                QRsize = userSize;
            }
        }
        if (QRsize == -1) {
            if (userSize === 0) {
                if (errorLevel === 'H') {
                    alert('二维码内容长度已超过当前设置的最大长度。');
                } else {
                    alert('二维码内容长度已超过当前设置的最大长度。请尝试在「高级选项」中减少容错率。');
                }
            } else {
                alert('二维码内容已超过最大长度。请尝试在「高级选项」中增大尺寸或减少容错率。');
            }
            return;
        }

        var qr = qrcode(QRsize, errorLevel);
        qr.addData(text);
        qr.make();

        var controls = qrcode(QRsize, errorLevel);
        controls.addData(text);
        controls.make(true);

        halftoneQR(qr.returnByteArray(), controls.returnByteArray());

    });

    // First load (cat)
    var imageColour = new Image();
    imageColour.onload = function() {
        has_image = true;
        image = this;
        $('#button-generate').triggerHandler('click');
    }
    imageColour.src = '';

});
